#!/bin/bash

DAYS_SECONDS_90=$((90 * 24 * 60 * 60))

log::init() {
  . $ZMICRO_CORE_PATH/os
  . $ZMICRO_CORE_PATH/color

  local current_user=$(os::username)

  if [ "$current_user" = "" ]; then
    log::error "log::init can not get current user."
    exit 1
  fi

  # @TODO
  if [ -z "$ZMICRO_LOG_PATH" ]; then
    ZMICRO_LOG_PATH=/var/log/zmicro
  fi

  # # echo "[init] config log"
  if [ ! -d $ZMICRO_LOG_PATH ]; then
    sudo mkdir -p $ZMICRO_LOG_PATH
    sudo chown -R $current_user $ZMICRO_LOG_PATH

    # @TODO load core os utils
    log::debug "[log::init] internal log current User: sudo chown -R $current_user $ZMICRO_LOG_PATH"
  fi

  if [ ! -d $ZMICRO_APP_LOGS_PATH ]; then
    sudo mkdir -p $ZMICRO_APP_LOGS_PATH
    sudo chown -R $current_user $ZMICRO_APP_LOGS_PATH

    log::debug "[log::init] logs current User: sudo chown -R $current_user $ZMICRO_LOG_PATH"
  fi

  if [ ! -w $ZMICRO_LOG_PATH ]; then
    sudo chown -R $current_user $ZMICRO_LOG_PATH
  fi

  if [ ! -w $ZMICRO_APP_LOGS_PATH ]; then
    sudo chown -R $current_user $ZMICRO_APP_LOGS_PATH
  fi

  log::debug "logs config done"
}

log::info() {
  echo -e "$(color::green ℹ) ${@}" | tee -a $ZMICRO_LOG_COMMON_PATH
}

log::debug() {
  echo -e $@ >>$ZMICRO_LOG_DEBUG_PATH
}

log::success() {
  echo "$(color::green ✔) ${@}" | tee -a $ZMICRO_LOG_COMMON_PATH
}

log::error() {
  echo "$(color::red ✖) ${@}" | tee -a $ZMICRO_LOG_ERROR_PATH
}

log::warn() {
  echo -e "$(color::yellow ⚠) ${@}" | tee -a $ZMICRO_LOG_COMMON_PATH
}

log() {
  # @TODO will remove custum blanks
  echo -e $@ | tee -a $ZMICRO_LOG_COMMON_PATH
  # log::info $@
}

log::timestamp() {
  echo -e "[$(timestamp)] $@"
}

log::command() {
  local command_path_with_seperator=$1

  # Run Command with log
  local base_command_path=$(echo $command_path_with_seperator | cut -d "#" -f 1)
  local command_fragments=$(echo $command_path_with_seperator | cut -d "#" -f 2)
  local command_args=$(echo $command_path_with_seperator | cut -d "#" -f 3-)
  # Init Script Path
  local init_path=$base_command_path/_init

  log::debug "[$(timestamp)]$(color::success [command] command path: $base_command_path $command_fragments $command_args)"
  log::debug "[$(timestamp)][command]"

  # log::debug "origin: $@"
  log::debug "[$(timestamp)][command] base_command_path: $base_command_path"
  log::debug "[$(timestamp)][command] command_fragments: $command_fragments"
  log::debug "[$(timestamp)][command] command_args: $command_args"
  log::debug "[$(timestamp)][command] init_path: $init_path"
  log::debug "[$(timestamp)][command]"

  # @TODO
  if [ "$command_fragments" = "unknown" ]; then
    echo "[error] found, but commander::get_command_path error"
    exit 1
  fi

  command_path=$(commander::get_command_path_with_fragments $base_command_path $command_fragments)

  echo -e "${GREEN}[$(timestamp)] $command_fragments start ...${ENDCOLOR}" >>$ZMICRO_LOG_COMMON_PATH

  log::debug [$(timestamp)]$(color::success "[command] final command path: $command_path")
  log::debug ""

  # Load Init
  if [ -f "$init_path" ]; then
    log::debug "[$(timestamp)][command] load init in $init_path"

    # . $init_path
    config::load_file $init_path
  fi

  # @TODO if use log command, donot record log, caused bug
  echo "$command_path" | grep "commands/_internal/log" >>/dev/null
  if [ "$?" = "0" ]; then
    $command_path $command_args
    exit_code=${PIPESTATUS[0]}
  else
    $command_path $command_args # | tee -a $ZMICRO_LOG_COMMON_PATH
    exit_code=${PIPESTATUS[0]}
    # echo "exit_code: $exit_code($command)"
  fi

  if [ "$exit_code" = "0" ]; then
    log::success "[$(timestamp)] $command_fragments done." >>/dev/null # >> $ZMICRO_LOG_COMMON_PATH
  else
    log::error "[$(timestamp)] $command_fragments error." >>$ZMICRO_LOG_COMMON_PATH
  fi

  exit $exit_code
}

log::update() {
  local type=$1 # CORE | PLUGIN
  local name=$2
  local stage=$3 # START | END | ERROR
  local origin_version=$4
  local current_version=$5

  # local current_version=$(version::get)
  if [ "$stage" = "START" ]; then
    if [ "$type" = "CORE" ]; then
      current_version=$(version::get)
    else
      current_version=$origin_version
    fi

    log::info "[$(timestamp)][${type}: ${name}][${stage}] ${current_version}" >>$ZMICRO_LOG_UPDATE_PATH
  else
    if [ "$origin_version" = "$current_version" ]; then
      log::info "[$(timestamp)][${type}: ${name}][${stage}][version] ${origin_version} => ${current_version}" >>$ZMICRO_LOG_UPDATE_PATH
    else
      log::info "[$(timestamp)][${type}: ${name}][${stage}][version] ${origin_version} => $(color::green ${current_version})" >>$ZMICRO_LOG_UPDATE_PATH
    fi
  fi

  if [ "$type" = "CORE" ]; then
    echo "====== DETAIL LOG ${stage} ======" >>$ZMICRO_LOG_UPDATE_PATH
  else
    echo "  ====== DETAIL LOG ${stage} ======" >>$ZMICRO_LOG_UPDATE_PATH
  fi

  if [ "$stage" = "END" ] || [ "$stage" = "ERROR" ]; then
    if [ "$type" = "CORE" ] && [ "$name" = "zmicro" ]; then
      echo "" >>$ZMICRO_LOG_UPDATE_PATH
      echo "" >>$ZMICRO_LOG_UPDATE_PATH
    fi
  fi
}

log::version() {
  local PREV=$1
  local CURRENT=$2

  if [ "$PREV" != "$CURRENT" ]; then
    log::info "[$(timestamp)][$CURRENT] ${PREV} => ${CURRENT}"
    log::success "update success: $CURRENT"
  else
    log::success "no changes: $CURRENT"
  fi
}

log::plugin_update_lock() {
  # format: plugin_name#timestamps
  # example: daemon#timestamps
  if [ -z "$plugin_name" ]; then
    log::error "[log::plugin_update_lock] plugin_name is required"
    exit 1
  fi

  local msg="$plugin_name#$(timestamp)"
  # sed -i "/^\s*$/d" $ZMICRO_LOCK_UPDATE_PATH

  # @TODO @TODO @TODO
}

# keep in 90d
log::clean_check() {
  local log_last_check=$ZMICRO_LOG_PATH/.last_clean

  # initialize
  if [ ! -f $log_last_check ]; then
    echo "$(timestamp)" | sudo tee $log_last_check >>/dev/null 2>&1

    # clean
    log::clean &
    >>/dev/null 2>&1
    return
  fi

  local last_check_timestamp=$(cat $log_last_check)
  if [ -z "$last_check_timestamp" ]; then
    echo "$(timestamp)" | sudo tee $log_last_check >>/dev/null 2>&1
    return
  fi

  local lcts=$(timestamp::to_seconds $last_check_timestamp)
  if [ "$?" != "0" ]; then
    echo "$(timestamp)" | sudo tee $log_last_check >>/dev/null 2>&1
    return
  fi

  local now=$(date +%s)
  local delta=$((now - lcts))
  # will rm logs after 90 days
  # echo "delta: $delta"
  if [ $delta -gt $DAYS_SECONDS_90 ]; then
    # do clean
    log::clean # & >> /dev/null 2>&1
    # else
    # echo "[log::clean_check] no need clean"
  fi
}

log::clean() {
  # if [ ! -d $ZMICRO_LOG_PATH ]; then
  #   export ZMICRO_LOG_PATH=${LOG_CLEAN_DIR}
  # fi

  local LOG_CLEAN_DIR=$ZMICRO_LOG_PATH
  # if [ -d "$LOG_CLEAN_DIR" ]; then
  #   LOG_CLEAN_DIR=/var/log/zmicro
  # fi

  # if [ "$(string::match $LOG_CLEAN_DIR ^${/var/log/zmicro})"]; then
  #   LOG_CLEAN_DIR=/var/log/zmicro
  # fi

  echo "$LOG_CLEAN_DIR" | grep zmicro >>/dev/null 2>&1
  if [ "$?" != "0" ]; then
    LOG_CLEAN_DIR=/var/log/zmicro
  fi

  local LOG_CLEAN_BACKUP_FILE=${LOG_CLEAN_DIR}/backup.$(date +%Y-%m-%d_%H_%M_%S).gz
  log::debug "[timestamps][log::clean] clean logs dir: ${ZMICRO_LOG_PATH}"

  # backup
  log::debug "[timestamps][log::clean] backup ${LOG_CLEAN_BACKUP_FILE}"
  sudo tar -zcvf ${LOG_CLEAN_BACKUP_FILE} --exclude '*.gz' ${LOG_CLEAN_DIR} >>/dev/null 2>&1
  if [ -f "$LOG_CLEAN_BACKUP_FILE" ]; then
    # @TODO safe
    sudo rm -rf ${LOG_CLEAN_DIR}/*.log >>/dev/null 2>&1
    # sudo rm -rf /var/log/zmicro/*.log >> /dev/null 2>&1
  fi

  # retimestamp
  local log_last_check=$ZMICRO_LOG_PATH/.last_clean
  echo "$(timestamp)" | sudo tee $log_last_check >>/dev/null 2>&1
}

export -f log::init

export -f log::clean_check
export -f log::clean

export -f log
export -f log::success
export -f log::debug
export -f log::error
export -f log::info
export -f log::warn

export -f log::timestamp

export -f log::command
export -f log::update
export -f log::version

export -f log::plugin_update_lock
